home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / HPACK78S.ZIP / amiga.c next >
C/C++ Source or Header  |  1992-11-26  |  26KB  |  896 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                              Amiga-Specific Routines                        *
  7. *                             AMIGA.C  Updated 20/11/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *             Copyright 1992  Peter C. Gutmann.  All rights reserved            *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. /* "The difference is not in the hardware, but in the operating system...
  19.     the Amiga has one, the PC has DOS" - James Pullen */
  20.  
  21. /* We can't include "defs.h" since some of the defines conflict with
  22.    built-in ones and Lattice/SAS C 5.10 doesn't seem to like them being
  23.    #undef'd and redefined, so we define the necessary defs.h defines here.
  24.  
  25.    "You're talking about an Amiga compiler here" - N.McB
  26.  
  27.    "It could be seen as a very good argument for believing in some form of
  28.     divine retribution" - Arne Rohde
  29.  
  30.    "This compiler has a plethora of insects" - Misquote from the Amiga Rom
  31.                                                Kernel Reference Manual */
  32.  
  33. typedef unsigned char    BOOLEAN;
  34.  
  35. #define FALSE    0
  36. #define TRUE    1
  37.  
  38. #define OK        0
  39. #define ERROR    -1
  40.  
  41. #define inline
  42.  
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46.  
  47. #include <proto/dos.h>    /* PNM 18 Nov 1992 */
  48. #include <proto/exec.h>
  49. #include <proto/icon.h>
  50. #include <exec/memory.h>
  51. #include <workbench/workbench.h>
  52.  
  53. #define _DEFS_DEFINED    /* Trick crc16.h into not #including defs.h */
  54.  
  55. #include "error.h"
  56. #include "filesys.h"
  57. #include "flags.h"
  58. #include "frontend.h"
  59. #include "system.h"
  60. #include "tags.h"
  61. #include "hpacklib.h"
  62. #include "io/hpackio.h"
  63. #include "io/fastio.h"
  64. #include "crc/crc16.h"
  65.  
  66. /* The time difference between the Amiga and Unix epochs, in seconds */
  67.  
  68. #define AMIGA_TIME_OFFSET        0x0F0C3F00L
  69.  
  70. /* DICE doesn't seem to have MODE_READWRITE defined */
  71.  
  72. #ifndef MODE_READWRITE
  73.   #define MODE_READWRITE        1004
  74. #endif /* !MODE_READWRITE */
  75.  
  76. /* The maximum length of a file comment (80 chars + '\0') */
  77.  
  78. #define COMMENT_SIZE            81
  79.  
  80. /* AmigaDOS handles all files in terms of a FileHandle struct.  The HPACK
  81.    routines can be generalized to handle this, but it's far easier to simply
  82.    add our own file table management code */
  83.  
  84. typedef struct DiskObject        DISKOBJECT;
  85. typedef struct FileHandle        FILEHANDLE;
  86. typedef struct FileInfoBlock    FILEINFOBLOCK;
  87. typedef struct FileLock            LOCK;
  88. typedef struct Image            IMAGE;
  89. typedef struct Message            MESSAGE;
  90. typedef struct MsgPort            MSGPORT;
  91. typedef struct StandardPacket    STANDARDPACKET;
  92.  
  93. #define MAX_HANDLES        20
  94.  
  95. static FILEHANDLE *fileTable[ MAX_HANDLES ] = { NULL };
  96.  
  97. /* Find a free entry in the file table */
  98.  
  99. static int getHandle( void )
  100.     {
  101.     int i;
  102.  
  103.     /* Search the file table for a free handle */
  104.     for( i = 0; i < MAX_HANDLES; i++ )
  105.         if( fileTable[ i ] == NULL )
  106.             return( i );
  107.  
  108.     /* File table full */
  109.     return( ERROR );
  110.     }
  111.  
  112. /* Free a file table entry */
  113.  
  114. static inline void freeHandle( const FD theFile )
  115.     {
  116.     fileTable[ theFile ] = NULL;
  117.     }
  118.  
  119. /* All directories are accessed via read locks.  If an error occurs, we have
  120.    to clear the read locks or they can't be written to any more.  We do this
  121.    by keeping a global table of locks and stepping through unlocking
  122.    directories when we perform an error exit */
  123.  
  124. #define MAX_LOCKS        25
  125.  
  126. static LOCK *lockTable[ MAX_LOCKS ] = { NULL };
  127. static int lockCount = 0;
  128.  
  129. static inline void addLock( const LOCK *theLock )
  130.     {
  131.     if( lockCount < MAX_LOCKS )
  132.         lockTable[ lockCount++ ] = theLock;
  133.     else
  134.         /* Should never happen */
  135.         puts( "Lock table overflow" );
  136.     }
  137.  
  138. static inline void clearLastLock( void )
  139.     {
  140.     if( lockCount )
  141.         lockTable[ --lockCount ] = NULL;
  142.     else
  143.         /* Should never happen */
  144.         puts( "Lock table underflow" );
  145.     }
  146.  
  147. void clearLocks( void )
  148.     {
  149.     while( lockCount )
  150.         {
  151.         UnLock( ( BPTR ) lockTable[ --lockCount ] );
  152.         lockTable[ lockCount ] = NULL;
  153.         }
  154.     }
  155.  
  156. /****************************************************************************
  157. *                                                                            *
  158. *                                HPACKIO Functions                            *
  159. *                                                                            *
  160. ****************************************************************************/
  161.  
  162. /* Create a new file - use Open() with the MODE_NEWFILE parameter */
  163.  
  164. FD hcreat( const char *fileName, const int attr )
  165.     {
  166.     FILEHANDLE *theHandle;
  167.     FD theFD;
  168.  
  169.     if( ( theHandle = ( FILEHANDLE * ) Open( fileName, MODE_NEWFILE ) ) == NULL || \
  170.         ( theFD = getHandle() ) == ERROR )
  171.         return( ERROR );
  172.  
  173.     fileTable[ theFD ] = theHandle;
  174.     return( theFD );
  175.     }
  176.  
  177. /* Open an existing file */
  178.  
  179. FD hopen( const char *fileName, const int mode )
  180.     {
  181.     FILEHANDLE *theHandle;
  182.     LONG openMode = ( mode != S_DENYNONE ) ? MODE_READWRITE : MODE_OLDFILE;
  183.     FD theFD;
  184.  
  185.     if( ( theHandle = ( FILEHANDLE * ) Open( fileName, openMode ) ) == NULL || \
  186.         ( theFD = getHandle() ) == ERROR )
  187.         return( ERROR );
  188.  
  189.     fileTable[ theFD ] = theHandle;
  190.     return( theFD );
  191.     }
  192.  
  193. /* Close a file */
  194.  
  195. int hclose( const FD theFile )
  196.     {
  197.     Close( ( BPTR ) fileTable[ theFile ] );
  198.     freeHandle( theFile );
  199.     return( OK );
  200.     }
  201.  
  202. /* Read data from a file */
  203.  
  204. int hread( const FD theFile, void *buffer, const unsigned int count )
  205.     {
  206.     return( ( int ) Read( ( BPTR ) fileTable[ theFile ], buffer, ( long ) count ) );
  207.     }
  208.  
  209. /* Write data to a file */
  210.  
  211. int hwrite( const FD theFile, void *buffer, const unsigned int count )
  212.     {
  213.     return( ( int ) Write( ( BPTR ) fileTable[ theFile ], buffer, ( long ) count ) );
  214.     }
  215.  
  216. /* Seek to a position in a file */
  217.  
  218. long hlseek( const FD theFile, const long offset, const int origin )
  219.     {
  220.     /* The AmigaDOS Seek() call returns the *previous* position rather than
  221.        the current one, so we need to perform two calls, one to move the
  222.        pointer and a second one to find out where we now are.  In addition
  223.        the origin codes are SEEK_SET = -1, SEEK_CURR = 0, SEEK_END = 1 so
  224.        we subtract one from the given codes to get the Amiga ones */
  225.     if( Seek( ( BPTR ) fileTable[ theFile ], offset, ( long ) origin - 1 ) != IO_ERROR )
  226.         return( Seek( ( BPTR ) fileTable[ theFile ], 0L, OFFSET_CURRENT ) );
  227.     else
  228.         return( IO_ERROR );
  229.     }
  230.  
  231. /* Return the current position in a file */
  232.  
  233. long htell( const FD theFile )
  234.     {
  235.     return( Seek( ( BPTR ) fileTable[ theFile ], 0L, OFFSET_CURRENT ) );
  236.     }
  237.  
  238. /* Truncate a file at the current position.  Needs KS 2.0 or above.  Under
  239.    KS 1.3 it's possible by sending an ACTION_SET_FILE_SIZE packet to the
  240.    file handler */
  241.  
  242. int htruncate( const FD theFile )
  243.     {
  244.     return( ( SetFileSize( theFile, OFFSET_BEGINNING, htell( theFile ) ) != IO_ERROR ) ? \
  245.             OK : IO_ERROR );
  246.     }
  247.  
  248. /* Remove a file */
  249.  
  250. int hunlink( const char *fileName )
  251.     {
  252.     return( DeleteFile( fileName ) ? OK : ERROR );
  253.     }
  254.  
  255. /* Create a directory.  Since the lock is only transient, we don't bother
  256.    adding it to the lock table */
  257.  
  258. int hmkdir( const char *dirName, const int attr )
  259.     {
  260.     LOCK *dirLock;
  261.  
  262.     if( ( dirLock = ( LOCK * ) CreateDir( dirName ) ) == NULL )
  263.         return( ERROR );
  264.     UnLock( ( BPTR ) dirLock );
  265.     return( OK );
  266.     }
  267.  
  268. /* Rename a file */
  269.  
  270. int hrename( const char *oldName, const char *newName )
  271.     {
  272.     return( Rename( oldName, newName ) ? OK : ERROR );
  273.     }
  274.  
  275. /* Set/change a file's attributes */
  276.  
  277. int hchmod( const char *fileName, const WORD attr )
  278.     {
  279.     return( SetProtection( fileName, ( long ) attr ) ? OK : ERROR );
  280.     }
  281.  
  282. /****************************************************************************
  283. *                                                                            *
  284. *                                HPACKLIB Functions                            *
  285. *                                                                            *
  286. ****************************************************************************/
  287.  
  288. /* Modes for the CON: handler (raw and cooked) */
  289.  
  290. #define CON_MODE    0
  291. #define RAW_MODE    1
  292.  
  293. /* Get a char, no echo.  Needs KS 2.0 or above.  Under KS 1.x it's possible
  294.    by sending an ACTION_SCREEN_MODE packet to the console handler */
  295.  
  296. int hgetch( void )
  297.     {
  298.     int ch;
  299.  
  300.     SetMode( Input(), RAW_MODE );
  301.     Write( Output(), "\x1b[20l", 5 );    /* Turn off CRLF translation */
  302.     ch = getchar();
  303.     SetMode( Input(), CON_MODE );
  304.     return( ch );
  305.     }
  306.  
  307. /****************************************************************************
  308. *                                                                            *
  309. *                                SYSTEM Functions                            *
  310. *                                                                            *
  311. ****************************************************************************/
  312.  
  313. /* Set a file's timestamp.  Needs KS 2.0.  Under 1.2 or 1.3 it's possible by
  314.    sending an ACTION_SET_DATE packet to the file's handler */
  315.  
  316. #define SECS_PER_DAY    86400        /* Seconds per day */
  317.  
  318. void setFileTime( const char *fileName, const LONG fileTime )
  319.     {
  320.     struct DateStamp dateStamp;
  321. #if 0
  322.     MSGPORT *taskPort;
  323.     LOCK *dirLock, *fileLock;
  324.     MSGPORT *replyPort;
  325.     STANDARDPACKET packet;
  326.     char pFileName[ MAX_FILENAME + 1 ];
  327. #endif /* 0 */
  328.     long seconds;
  329.  
  330.     /* Extract the day, minute, tick counts and put in the DateStamp structure */
  331.     seconds = fileTime - AMIGA_TIME_OFFSET;
  332.     dateStamp.ds_Days  = seconds / SECS_PER_DAY;
  333.     seconds %= SECS_PER_DAY;
  334.     dateStamp.ds_Minute  = seconds / 60;
  335.     dateStamp.ds_Tick = ( seconds % 60 ) * TICKS_PER_SECOND;
  336.  
  337.     /* Set the timestamp */
  338.     SetFileDate( fileName, &dateStamp );
  339.  
  340. #if 0
  341.     /* Try and open a message port to the file, and put a lock on it */
  342.     if( ( taskPort = ( MSGPORT * ) DeviceProc( fileName ) ) == NULL || \
  343.         ( fileLock = ( LOCK * ) Lock( fileName, SHARED_LOCK ) ) == NULL )
  344.         return;
  345.  
  346.     /* Get a lock on the directory containing the file, and convert the
  347.        filename to a Pascal string (euurgghh, Macintoshness!) */
  348.     dirLock = ( LOCK * ) ParentDir( fileLock );
  349.     UnLock( fileLock );
  350.     strcpy( pFileName + 1, findFilenameStart( fileName ) );
  351.     *pFileName = strlen( pFileName + 1 );
  352.  
  353.     /* Get a port for the message reply */
  354.     if( replyPort = ( MSGPORT * ) CreatePort( 0L, 0L ) != NULL )
  355.         {
  356.         /* Set up the packet to send */
  357.         packet.sp_Msg.mn_Node.ln_Name = ( char * ) &( packet.sp_Pkt );
  358.         packet.sp_Pkt.dp_Link = &( packet.sp_Msg );
  359.         packet.sp_Pkt.dp_Port = replyPort;
  360.         packet.sp_Pkt.dp_Type = ACTION_SET_DATE;
  361.         packet.sp_Pkt.dp_Arg1 = ( LONG ) NULL;
  362.         packet.sp_Pkt.dp_Arg2 = ( LONG ) dirLock;
  363.         packet.sp_Pkt.dp_Arg3 = ( LONG ) pFileName >> 2;
  364.         packet.sp_Pkt.dp_Arg4 = ( LONG ) &dateStamp;
  365.  
  366.         /* Send the message and wait for a reply */
  367.         PutMsg( taskPort, ( MESSAGE * ) &packet );
  368.         WaitPort( replyPort );
  369.         GetMsg( replyPort );    /* Status = packet.sp_Pkt.dp_Res1 */
  370.         DeletePort( replyPort );
  371.         }
  372.  
  373.     /* Clean up */
  374.     UnLock( dirLock );
  375. #endif /* 0 */
  376.     }
  377.  
  378. #ifndef GUI
  379.  
  380. /* The following two functions aren't needed for the GUI version */
  381.  
  382. #define DEFAULT_ROWS        24
  383. #define DEFAULT_COLS        80
  384.  
  385. void getScreenSize( void )
  386.     {
  387.     /* Not really appropriate so just default to 24x80 */
  388.     screenWidth = DEFAULT_COLS;
  389.     screenHeight = DEFAULT_ROWS;
  390.     }
  391.  
  392. int getCountry( void )
  393.     {
  394.     return( 0 );    /* Default to US */
  395.     }
  396. #endif /* GUI */
  397.  
  398. /* Find the first/next file in a directory.  The Amiga requires that a
  399.    lock be placed on a directory before it is accessed.  These functions
  400.    try to unlock a directory as soon as possible once they've finished with
  401.    it rather than relying on findEnd(), to allow other processes to access
  402.    the information as well */
  403.  
  404. static void getFileInfo( FILEINFO *fileInfo )
  405.     {
  406.     FILEINFOBLOCK *infoBlock = ( FILEINFOBLOCK * ) fileInfo->infoBlock; /* Took "&" off parameter, PNM 22 Nov 92 */
  407.  
  408.     /* Copy relevant fields across to fileInfo block.  When converting the
  409.        timestamp we approximate 1 tick == 1 second, which is close enough */
  410.     fileInfo->isDir = infoBlock->fib_DirEntryType > 0;
  411.     strcpy( fileInfo->fName, infoBlock->fib_FileName );
  412.     fileInfo->fSize = infoBlock->fib_Size;
  413.     fileInfo->fTime = AMIGA_TIME_OFFSET + \
  414.                       ( infoBlock->fib_Date.ds_Days * 86400 ) + \
  415.                       ( infoBlock->fib_Date.ds_Minute * 60 ) + \
  416.                       ( infoBlock->fib_Date.ds_Tick / TICKS_PER_SECOND );
  417.     fileInfo->fAttr = infoBlock->fib_Protection;
  418.     fileInfo->hasComment = *infoBlock->fib_Comment ? TRUE : FALSE;
  419.     }
  420.  
  421. BOOLEAN findFirst( const char *pathName, const ATTR fileAttr, FILEINFO *fileInfo )
  422.     {
  423.     char filePath[ MAX_PATH ];
  424.     int filePathLen = strlen( ( char * ) pathName );
  425.     BOOLEAN matchIndividual = TRUE;
  426.  
  427.     fileInfo->matchAttr = fileAttr;
  428.     fileInfo->infoBlock = NULL;
  429.  
  430.     /* If we want to open a directory we need to zap the slash to get a pure
  431.        directory path component */
  432.     strcpy( filePath, ( char * ) pathName );
  433.     if( !filePathLen )
  434.         /* No path, match all files in current directory */
  435.         matchIndividual = FALSE;
  436.     else
  437.         /* Check for whole-directory match */
  438.         if( filePath[ filePathLen - 1 ] == SLASH )
  439.             {
  440.             filePath[ filePathLen - 1 ] = '\0';
  441.             matchIndividual = FALSE;
  442.             }
  443.  
  444.     /* Place a lock on the file/directory, allocate room for the
  445.        information, and get it */
  446.     if( ( fileInfo->infoBlock = AllocMem( sizeof( FILEINFOBLOCK ), \
  447.                                           MEMF_PUBLIC | MEMF_CLEAR ) ) == NULL )
  448.         error( OUT_OF_MEMORY );
  449.     if( ( fileInfo->lock = ( void * ) Lock( filePath, ACCESS_READ ) ) == NULL )
  450.         return( FALSE );
  451.     if( !Examine( ( BPTR ) fileInfo->lock, \
  452.                   ( FILEINFOBLOCK * ) fileInfo->infoBlock ) ) /* Took "&" off parameter, PNM 22 Nov 92 */
  453.         {
  454.         UnLock( ( BPTR ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
  455.         fileInfo->lock = NULL;
  456.         FreeMem( fileInfo->infoBlock, sizeof( FILEINFOBLOCK ) );
  457.         fileInfo->infoBlock = NULL;
  458.         return( FALSE );
  459.         }
  460.     addLock( ( LOCK * ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
  461.     getFileInfo( fileInfo );
  462.  
  463.     /* If we're looking for files within a directory, we need to call
  464.        findNext() since the Examine() call will read the parent directory
  465.        not it's contents.  ExNext() reads the contents */
  466.     if( !matchIndividual )
  467.         return( findNext( fileInfo ) );
  468.  
  469.     /* Return FALSE if we've found the wrong type of file */
  470.     return( ( fileInfo->matchAttr != FILES_DIRS && fileInfo->isDir ) ? \
  471.             FALSE : TRUE );
  472.     }
  473.  
  474. BOOLEAN findNext( FILEINFO *fileInfo )
  475.     {
  476.     do
  477.         /* Try and get info on the next file/dir */
  478.         if( !ExNext( ( BPTR ) fileInfo->lock, \
  479.                      ( FILEINFOBLOCK * ) fileInfo->infoBlock ) ) /* Took "&" off parameter, PNM 22 Nov 92 */
  480.             {
  481.             UnLock( ( BPTR ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
  482.             clearLastLock();
  483.             fileInfo->lock = NULL;
  484.             FreeMem( fileInfo->infoBlock, sizeof( FILEINFOBLOCK ) );
  485.             fileInfo->infoBlock = NULL;
  486.             return( FALSE );
  487.             }
  488.     /* Sometimes we only want to match files, not directories */
  489.     while( ( fileInfo->matchAttr == ALLFILES ) ? \
  490.            ( ( FILEINFOBLOCK * ) fileInfo->infoBlock)->fib_DirEntryType > 0 : 0 );
  491.  
  492.     getFileInfo( fileInfo );
  493.     return( TRUE );
  494.     }
  495.  
  496. void findEnd( FILEINFO *fileInfo )
  497.     {
  498.     /* Unlock the directory (rarely used since it's usually done by findNext()) */
  499.     if( fileInfo->lock != NULL )
  500.         {
  501.         UnLock( ( BPTR ) fileInfo->lock ); /* Took "&" off parameter, PNM 22 Nov 92 */
  502.         clearLastLock();
  503.         fileInfo->lock = NULL;
  504.         }
  505.  
  506.     /* Free the memory used by the FileInfoBlock (also rarely used since
  507.        findNext() does it */
  508.     if( fileInfo->infoBlock != NULL )
  509.         {
  510.         FreeMem( fileInfo->infoBlock, sizeof( FILEINFOBLOCK ) );
  511.         fileInfo->infoBlock = NULL;
  512.         }
  513.     }
  514.  
  515. /* Store the comment for a file/directory in an archive in HPACK tagged format */
  516.  
  517. int storeComment( const FILEINFO *fileInfo, const FD outFD )
  518.     {
  519.     int commentLength = strlen( ( ( FILEINFOBLOCK * ) fileInfo->infoBlock )->fib_Comment );
  520.     int dataLength = commentLength, i;
  521.     BOOLEAN isDir = !outFD;
  522.  
  523.     /* Write the comment tag header */
  524.     if( isDir )
  525.         dataLength += addDirData( TAG_COMMENT, TAGFORMAT_STORED, commentLength, LEN_NONE );
  526.     else
  527.         dataLength += writeTag( TAG_COMMENT, TAGFORMAT_STORED, commentLength, LEN_NONE );
  528.  
  529.     /* Now write the comment data */
  530.     if( isDir )
  531.         {
  532.         /* Write comment to directory data area */
  533.         checksumDirBegin( RESET_CHECKSUM );
  534.         for( i = 0; i < commentLength; i++ )
  535.             fputDirByte( ( ( FILEINFOBLOCK * ) fileInfo->infoBlock )->fib_Comment[ i ] );
  536.         checksumDirEnd();
  537.         fputDirWord( crc16 );
  538.         }
  539.     else
  540.         {
  541.         /* Write comment to file data area */
  542.         checksumBegin( RESET_CHECKSUM );
  543.         for( i = 0; i < commentLength; i++ )
  544.             fputByte( ( ( FILEINFOBLOCK * ) fileInfo->infoBlock )->fib_Comment[ i ] );
  545.         checksumEnd();
  546.         fputWord( crc16 );
  547.         }
  548.  
  549.     return( dataLength + sizeof( WORD ) );
  550.     }
  551.  
  552. /* Set the comment for a file/directory from an HPACK tag */
  553.  
  554. void setComment( const char *filePath, const TAGINFO *tagInfo, const FD srcFD )
  555.     {
  556.     char comment[ COMMENT_SIZE ];
  557.     int i, commentSize = ( tagInfo->dataLength > COMMENT_SIZE - 1 ) ? \
  558.                          COMMENT_SIZE - 1 : tagInfo->dataLength;
  559.  
  560.     /* Make sure we can read the comment */
  561.     if( tagInfo->dataFormat != TAGFORMAT_STORED )
  562.         {
  563.         /* Don't know how to handle compressed comments yet, skip it */
  564.         skipSeek( tagInfo->dataLength );
  565.         return;
  566.         }
  567.  
  568.     /* Read in as much of the comment as we can, skip the rest */
  569.     for( i = 0; i < commentSize; i++ )
  570.         comment[ i ] = fgetByte();
  571.     comment[ i ] = '\0';
  572.     if( tagInfo->dataLength - commentSize )
  573.         skipSeek( tagInfo->dataLength - commentSize );
  574.  
  575.     /* Set the file's comment */
  576.     SetComment( filePath, comment );
  577.     }
  578.  
  579. /* Initialise/cleanup functions for extra info handling */
  580.  
  581. struct Library *IconLib = NULL;
  582.  
  583. void initExtraInfo( void )
  584.     {
  585.     /* Try and open icon library */
  586.     if( ( IconLib = OpenLibrary( "icon.library", 33 ) ) == NULL )
  587.         error( INTERNAL_ERROR );
  588.     }
  589.  
  590. void endExtraInfo( void )
  591.     {
  592.     /* Close icon library */
  593.     if( IconLib != NULL )
  594.         CloseLibrary( IconLib );
  595.     }
  596.  
  597. /* Set extra info for an archive, copy extra info from one file to another */
  598.  
  599. void setExtraInfo( const char *filePath )
  600.     {
  601.     /* The HPACK icon image (there should be four of these, one per file
  602.        type of normal, secured, encrypted, both) */
  603.  
  604.     __chip static UWORD hpackIconData[] = {
  605.                     /* Icon image data */
  606.         0xffff,
  607.         0x8001,
  608.         0x8001,
  609.         0x8001,
  610.         0x8001,
  611.         0x8001,
  612.         0x8001,
  613.         0x8001,
  614.         0x8001,
  615.         0x8001,
  616.         0x8001,
  617.         0x8001,
  618.         0x8001,
  619.         0x8001,
  620.         0x8001,
  621.         0xffff,
  622.  
  623.         0xffff,
  624.         0x8001,
  625.         0x8001,
  626.         0x8001,
  627.         0x8001,
  628.         0x8001,
  629.         0x8001,
  630.         0x8001,
  631.         0x8001,
  632.         0x8001,
  633.         0x8001,
  634.         0x8001,
  635.         0x8001,
  636.         0x8001,
  637.         0x8001,
  638.         0xffff
  639.         };
  640.  
  641.     static IMAGE hpackIconImage = {
  642.         0, 0,                /* Top corner */
  643.         16, 16, 2,            /* Width, height, depth */
  644.         hpackIconData,        /* Data */
  645.         0, 0,                /* PlanePick, PlaneOnOff */
  646.         NULL                /* Next image */
  647.         };
  648.  
  649.     /* The tool types for normal, secured, encrypted, and both, archives */
  650.     static BYTE *normalToolType[] = { "FILETYPE=HPAK", NULL };
  651.     static BYTE *securedToolType[] = { "FILETYPE=HPKS", NULL };
  652.     static BYTE *encrToolType[] = { "FILETYPE=HPKC", NULL };
  653.     static BYTE *bothToolType[] = { "FILETYPE=HPKB", NULL };
  654.  
  655.     /* The disk object for the HPACK icon */
  656.     static DISKOBJECT hpackIcon = {
  657.         WB_DISKMAGIC,            /* Magic number */
  658.         WB_DISKVERSION,            /* Structure version number */
  659.             {                    /* Embedded gadget structure */
  660.             NULL,                /* Next gadget pointer */
  661.             0, 0, 16, 16,        /* Left, top, width, height */
  662.             GADGIMAGE | GADGHBOX,    /* Flags (must use) */
  663.             GADGIMMEDIATE | RELVERIFY, /* Activ.flags (must use) */
  664.             BOOLGADGET,            /* Type (must use) */
  665.             &hpackIconImage,    /* Image data */
  666.             NULL, NULL, NULL, NULL, 0, NULL    /* Unused fields */
  667.             },
  668.         WBPROJECT,                /* Icon type */
  669.         "Hpack",                /* Default tool name */
  670.         normalToolType,            /* Tool type array */
  671.         NO_ICON_POSITION, NO_ICON_POSITION,    /* Put it anywhere */
  672.         NULL, NULL,                /* Unused fields */
  673.         20000                    /* Stack size for tool */
  674.         };
  675.  
  676.     /* Set the icon image and tool type depending on what the archive type is */
  677.     switch( cryptFlags & ( CRYPT_PKE_ALL | CRYPT_CKE_ALL | CRYPT_SIGN_ALL ) )
  678.         {
  679.         case CRYPT_PKE_ALL:
  680.         case CRYPT_CKE_ALL:
  681.             /* Encrypted archive */
  682.             hpackIcon.do_ToolTypes = encrToolType;
  683.             break;
  684.  
  685.         case CRYPT_SIGN_ALL:
  686.             /* Secured archive */
  687.             hpackIcon.do_ToolTypes = securedToolType;
  688.             break;
  689.  
  690.         case CRYPT_PKE_ALL | CRYPT_SIGN_ALL:
  691.         case CRYPT_CKE_ALL | CRYPT_SIGN_ALL:
  692.             /* Encrypted + secured archive */
  693.             hpackIcon.do_ToolTypes = bothToolType;
  694.             break;
  695.         }
  696.  
  697.     /* Write out the new disk object */
  698.     PutDiskObject( filePath, &hpackIcon );
  699.     }
  700.  
  701. void copyExtraInfo( const char *srcFilePath, const char *destFilePath )
  702.     {
  703.     DISKOBJECT *iconObject;
  704.  
  705.     /* Read in the .info data from the source and write it to the destination */
  706.     if( ( iconObject = GetDiskObject( srcFilePath ) ) != NULL )
  707.         {
  708.         PutDiskObject( destFilePath, iconObject );
  709.         FreeDiskObject( iconObject );
  710.         }
  711.     }
  712.  
  713. /* Store the DiskObject associated with a file/directory, in an archive in
  714.    HPACK tagged form */
  715.  
  716. #define calcImageSize(theImage)    ( ( ( ( theImage.Width ) + 15 ) & 0xFFF0 ) * \
  717.                                   theImage.Height * theImage.Depth )
  718.  
  719. LONG storeDiskObject( const char *pathName, const FD outFD )
  720.     {
  721.     DISKOBJECT *theObject;
  722.     int i, iconImageSize, iconLength;
  723.     BOOLEAN isDir = !outFD;
  724.     IMAGE *theImage;
  725.  
  726.     /* Try and get the DiskObject for the file/directory */
  727.     if( ( theObject = GetDiskObject( pathName ) ) == NULL )
  728.         return( 0L );
  729.  
  730.     /* Perform a few sanity checks on the icon information.  According to
  731.        the ROM Kernel reference manual we should only handle icons with the
  732.        following magic values set up */
  733.     if( ( theObject->do_Gadget.Flags & GADGIMAGE ) && \
  734.         ( theObject->do_Gadget.Activation == ( GADGIMMEDIATE | RELVERIFY ) ) && \
  735.         ( theObject->do_Gadget.GadgetType == BOOLGADGET ) )
  736.         {
  737.         /* It's a icon gadget, store it as an AMIGA_ICON tag */
  738.         theImage = ( IMAGE * ) theObject->do_Gadget.GadgetRender;
  739.         iconImageSize = calcImageSize( ( * theImage ) );
  740.         iconLength = sizeof( WORD ) + sizeof( WORD ) + sizeof( WORD ) + \
  741.                      sizeof( WORD ) + sizeof( WORD ) + sizeof( BYTE ) + \
  742.                      sizeof( BYTE ) + sizeof( BYTE) + iconImageSize + \
  743.                      sizeof( WORD );
  744.         if( isDir )
  745.             {
  746.             /* Write directory icon data */
  747.             addDirData( TAG_AMIGA_ICON, TAGFORMAT_STORED, iconLength, LEN_NONE );
  748.             checksumDirBegin( RESET_CHECKSUM );
  749.             fputDirWord( theImage->LeftEdge );
  750.             fputDirWord( theImage->TopEdge );
  751.             fputDirWord( theImage->Width );
  752.             fputDirWord( theImage->Height );
  753.             fputDirWord( theImage->Depth );
  754.             fputDirByte( theImage->PlanePick );
  755.             fputDirByte( theImage->PlaneOnOff );
  756.             fputDirByte( theObject->do_Type );
  757.             for( i = 0; i < iconImageSize; i++ )
  758.                 fputDirWord( theImage->ImageData[ i ] );
  759.             checksumDirEnd();
  760.             fputDirWord( crc16 );
  761.             }
  762.         else
  763.             {
  764.             /* Write file icon data */
  765.             writeTag( TAG_AMIGA_ICON, TAGFORMAT_STORED, iconLength, LEN_NONE );
  766.             checksumBegin( RESET_CHECKSUM );
  767.             fputWord( theImage->LeftEdge );
  768.             fputWord( theImage->TopEdge );
  769.             fputWord( theImage->Width );
  770.             fputWord( theImage->Height );
  771.             fputWord( theImage->Depth );
  772.             fputByte( theImage->PlanePick );
  773.             fputByte( theImage->PlaneOnOff );
  774.             fputByte( theObject->do_Type );
  775.             for( i = 0; i < iconImageSize; i++ )
  776.                 fputWord( theImage->ImageData[ i ] );
  777.             checksumEnd();
  778.             fputWord( crc16 );
  779.             }
  780.         }
  781.  
  782.     FreeDiskObject( theObject );
  783.     }
  784.  
  785. /* Set the icon for a file/directory */
  786.  
  787. static DISKOBJECT defaultDiskObject = {
  788.         WB_DISKMAGIC,            /* Magic number */
  789.         WB_DISKVERSION,         /* Structure version number */
  790.             {                    /* Embedded gadget structure */
  791.             NULL,                /* Next gadget pointer */
  792.             0, 0, 0, 0,            /* Left, top, width, height */
  793.             GADGIMAGE | GADGHCOMP,    /* Flags (must use) */
  794.             GADGIMMEDIATE | RELVERIFY,    /* Activ.flags (must use) */
  795.             BOOLGADGET,            /* Type (must use) */
  796.             NULL,                /* Image data */
  797.             NULL, NULL, NULL, NULL, 0, NULL    /* Unused fields */
  798.             },
  799.         WBPROJECT,                /* Icon type */
  800.         "",                        /* Default tool name */
  801.         NULL,                    /* Tool type array */
  802.         NO_ICON_POSITION, NO_ICON_POSITION,    /* Put it anywhere */
  803.         NULL, NULL,                /* Unused fields */
  804.         0L                        /* Stack size for tool */
  805.         };
  806.  
  807. void setIcon( const char *filePath, const TAGINFO *tagInfo, const FD srcFD )
  808.     {
  809.     DISKOBJECT *theObject;
  810.     IMAGE iconImage, *oldIconImage;
  811.     BYTE oldType;
  812.     int i, iconImageSize;
  813.  
  814.     /* Try and get an existing DiskObject for the file/directory */
  815.     if( ( theObject = GetDiskObject( filePath ) ) == NULL )
  816.         /* None exists yet, use default object */
  817.         theObject = &defaultDiskObject;
  818.  
  819.     /* Switch to new ImageData information */
  820.     oldType = theObject->do_Type;
  821.     oldIconImage = ( IMAGE * ) theObject->do_Gadget.GadgetRender;
  822.     theObject->do_Gadget.GadgetRender = ( APTR ) &iconImage;
  823.  
  824.     /* Set up the Image fields */
  825.     checksumSetInput( tagInfo->dataLength - sizeof( WORD ), RESET_CHECKSUM );
  826.     iconImage.LeftEdge = fgetWord();
  827.     iconImage.TopEdge = fgetWord();
  828.     iconImage.Width = fgetWord();
  829.     iconImage.Height = fgetWord();
  830.     iconImage.Depth = fgetWord();
  831.     iconImage.PlanePick = fgetWord();
  832.     iconImage.PlaneOnOff = fgetWord();
  833.     theObject->do_Type = fgetByte();
  834.     iconImageSize = calcImageSize( iconImage );
  835.     if( ( iconImage.ImageData = \
  836.         ( WORD * ) hmalloc( iconImageSize * sizeof( WORD ) ) ) == NULL )
  837.         error( OUT_OF_MEMORY );
  838.     for( i = 0; i < iconImageSize; i++ )
  839.         iconImage.ImageData[ i ] = fgetWord();
  840.     iconImage.NextImage = NULL;
  841.  
  842.     /* If the data was non-corrupted, set the new icon */
  843.     if( fgetWord() == crc16 )
  844.         PutDiskObject( filePath, theObject );
  845.  
  846.     /* Free up in-memory data structures */
  847.     hfree( iconImage.ImageData );
  848.     theObject->do_Gadget.GadgetRender = ( APTR ) oldIconImage;
  849.     theObject->do_Type = oldType;
  850.     FreeDiskObject( theObject );
  851.     }
  852.  
  853. #if defined( LATTICE ) && !defined( __SASC )
  854.  
  855. /* memcpy() which handles overlapping memory ranges */
  856.  
  857. void memmove( char *dest, char *src, int length )
  858.     {
  859.     int itmp = ( length + 7 ) >> 3;
  860.  
  861.     if( dest > src )
  862.         {
  863.         dest += length;
  864.         src += length;
  865.         switch( length & 3 )
  866.             {
  867.             case 0:    do {    *--dest = *--src;
  868.             case 7:            *--dest = *--src;
  869.             case 6:            *--dest = *--src;
  870.             case 5:            *--dest = *--src;
  871.             case 4:            *--dest = *--src;
  872.             case 3:            *--dest = *--src;
  873.             case 2:            *--dest = *--src;
  874.             case 1:            *--dest = *--src;
  875.                      } while( --itmp > 0 );
  876.             }
  877.         }
  878.     else
  879.         {
  880.         switch( length & 3 )
  881.             {
  882.             case 0:    do {    *dest++ = *src++;
  883.             case 7:            *dest++ = *src++;
  884.             case 6:            *dest++ = *src++;
  885.             case 5:            *dest++ = *src++;
  886.             case 4:            *dest++ = *src++;
  887.             case 3:            *dest++ = *src++;
  888.             case 2:            *dest++ = *src++;
  889.             case 1:            *dest++ = *src++;
  890.                      } while( --itmp > 0 );
  891.             }
  892.         }
  893.     /* This was added mainly to frighten you */
  894.     }
  895. #endif /* LATTICE && !__SASC */
  896.